package org.orbis.communicate.deleter;

import org.msgpack.MessagePackObject;
import org.msgpack.object.ArrayType;
import org.msgpack.object.IntegerType;
import org.msgpack.object.RawType;
import org.orbis.communicate.hash.Hashing;
import org.orbis.constants.Constants;

public class DeleterPackage implements Comparable<DeleterPackage>{
	private static final int TYPE_ID = Constants.DELETE_TYPE_ID;
	private static final int TYPE_CONTENT = Constants.DELETE_TYPE_CONTENT;
	private static final int TYPE_APPENDIX = Constants.DELETE_TYPE_APPENDIX;
	private static final int TYPE_INTFLAG = Constants.DELETE_TYPE_INTFLAG;
	private static final int TYPE_LONGFLAG = Constants.DELETE_TYPE_LONGFLAG;

	private String stringValue;
	private int intValue;
	private long longValue;
	private long hash;
	private int type;
	private int flagType;
	private int cluster;

	public DeleterPackage(boolean isContent, String string){
		this.stringValue = string;
		this.hash = Hashing.getTermHash(string);
		if(isContent) this.type = TYPE_CONTENT;
		else this.type = TYPE_APPENDIX;
	}

	public DeleterPackage(int flagType, int flagval){
		this.intValue = flagval;
		this.hash = flagval << 32 | flagval;
		this.type = TYPE_INTFLAG;
		this.flagType = flagType;
	}

	public DeleterPackage(int flagType, long flagVal){
		this.longValue = flagVal;
		this.hash = flagVal;
		this.type = TYPE_LONGFLAG;
		this.flagType = flagType;
	}

	public DeleterPackage(long ID){
		this.longValue = ID;
		this.hash = ID;
		this.type = TYPE_ID;
	}

	public void setCluster(int cluster){
		this.cluster = cluster;
	}

	public int type(){
		return type;
	}

	public String strval(){
		if(type == TYPE_CONTENT) return stringValue;
		return null;
	}

	public int flagType(){
		if(type == TYPE_INTFLAG || type == TYPE_LONGFLAG) return flagType;
		return Integer.MIN_VALUE;
	}

	public int intFlag(){
		if(type == TYPE_INTFLAG) return intValue;
		return Integer.MIN_VALUE;
	}

	public long longFlag(){
		if(type == TYPE_LONGFLAG) return longValue;
		return Long.MIN_VALUE;
	}

	public long ID(){
		if(type == TYPE_ID) return longValue;
		return Long.MIN_VALUE;
	}

	public long hash(){
		return hash;
	}

	public int cluster(){
		return cluster;
	}

	private static final int HEADER = 'p' << 24 | 'd' << 16 | 'e' << 8 | 'l';

	public ArrayType pack(){
		MessagePackObject[] object = new MessagePackObject[4];

		object[0] = IntegerType.create(HEADER);
		object[1] = IntegerType.create(type);
		object[2] = IntegerType.create(flagType);
		if(type == TYPE_ID || type == TYPE_LONGFLAG) object[3] = IntegerType.create(longValue);
		if(type == TYPE_INTFLAG) object[3] = IntegerType.create(intValue);
		if(type == TYPE_CONTENT || type == TYPE_APPENDIX) object[3] = RawType.create(stringValue);

		return ArrayType.create(object);
	}

	public static DeleterPackage unpack(ArrayType packed){
		MessagePackObject[] object = packed.asArray();

		if(object.length < 4) return null;
		if(object[0].isIntegerType() && object[0].asInt() != HEADER) return null;
		DeleterPackage pkg = new DeleterPackage(0);
		pkg.type = object[1].asInt();
		pkg.flagType = object[2].asInt();
		if(pkg.type == TYPE_ID || pkg.type == TYPE_LONGFLAG) pkg.longValue = object[3].asLong();
		if(pkg.type == TYPE_INTFLAG) pkg.intValue = object[3].asInt();
		if(pkg.type == TYPE_CONTENT || pkg.type == TYPE_APPENDIX) pkg.stringValue = object[3].asString();
		
		return pkg;
	}

	@Override
	public boolean equals(Object obj){
		if(obj instanceof DeleterPackage){
			DeleterPackage others = (DeleterPackage)obj;
			if(this.type == others.type){
				if(this.type == TYPE_ID || this.type == TYPE_LONGFLAG)
					if(this.longValue == others.longValue) return true;
				if(this.type == TYPE_CONTENT || this.type == TYPE_APPENDIX)
					if(this.stringValue.equals(others.stringValue)) return true;
				if(this.type == TYPE_INTFLAG && this.intValue == others.intValue) return true;
			}
		}
		return super.equals(obj);
	}

	@Override
	public int compareTo(DeleterPackage o){
		// Fifth sort
		if(this.type > o.type) return 1;
		if(this.type < o.type) return -1;
		if(this.cluster > o.cluster) return 1;
		if(this.cluster < o.cluster) return -1;
		if(this.type == TYPE_ID || this.type == TYPE_LONGFLAG){
			if(this.longValue > o.longValue) return 1;
			if(this.longValue < o.longValue) return -1;
		}
		if(this.type == TYPE_CONTENT || this.type == TYPE_APPENDIX){
			if(this.stringValue.compareTo(o.stringValue) > 0) return 1;
			if(this.stringValue.compareTo(o.stringValue) < 0) return -1;
		}
		if(this.type == TYPE_INTFLAG && this.intValue > o.intValue) return 1;
		if(this.type == TYPE_INTFLAG && this.intValue < o.intValue) return -1;
		return 0;
	}
}
